from rest_framework import serializers
from orders.models import OrdersModel, OrdersDetailModel
from doctors.models import DoctorModel, AnswerModel
from django_redis import get_redis_connection
from orders.models import CouponLogModel
from django.db import transaction
import datetime
import traceback


class OrderModelSerializer(serializers.ModelSerializer):
    user_coupon_id = serializers.IntegerField(write_only=True, default=None)
    doctor_id = serializers.IntegerField(write_only=True, default=None)
    patients_id = serializers.IntegerField(write_only=True, default=None)
    discount_name = serializers.CharField(max_length=50, write_only=True, default=None)
    is_public = serializers.BooleanField(write_only=True, default=None)
    pay_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)
    real_price = serializers.DecimalField(max_digits=8, decimal_places=2, default=0, read_only=True)

    class Meta:
        model = OrdersModel
        fields = ['id', 'pay_type', 'order_number', 'pay_time', 'user_coupon_id', 'doctor_id',
                  'discount_name', 'is_public', 'patients_id', 'real_price']
        extra_kwargs = {
            'pay_type': {'write_only': True},
            'order_number': {'read_only': True},
        }

    # 新增数据
    def create(self, validated_data):
        # 往订单表中添加新订单
        # 获取用户，上下文context 获取
        user = self.context['request'].user
        user_id = user.id
        # 获取医生id
        doctor_id = int(validated_data.get('doctor_id', 0))
        patients_id = validated_data.get('patients_id', 0)
        # 获取当前用户的下单商品，获取问题的redis链接对象
        redis = get_redis_connection('answer')
        # 根据用户id和医生id获取当前用户所有问题数据
        answer_hash = redis.hgetall(f'{user_id}:{doctor_id}:{patients_id}:1')
        is_commit = redis.hget(f'{user_id}:{doctor_id}:{patients_id}:1', 'is_commit').decode()
        # 判断问题是否存在，并且是否未提交过
        if len(answer_hash) < 1:
            raise serializers.ValidationError(detail='没有提交的问题', code='answer_empty')
        if is_commit == '1':
            raise serializers.ValidationError(detail='问题已经被提交过', code='answer_error')

        # 优惠劵 获取用户使用的优惠劵
        user_coupon_id = validated_data.get('user_coupon_id', None)
        user_coupon1 = None
        if user_coupon_id is not None and user_coupon_id != 0:
            user_coupon1 = CouponLogModel.objects.filter(id=user_coupon_id, user_id=user_id).first()

        # 创建订单操作   开启数据库事务
        with transaction.atomic():
            # 创建事务的还原点
            t1 = transaction.savepoint()
            try:
                orders = OrdersModel.objects.create(
                    name='丁香医生购买下单',
                    user_id=user_id,
                    # 生成订单号                                                                        会导致位数不一致
                    order_number=datetime.datetime.now().strftime('%Y%m%d') + str('%08d' % user_id) + '%08d' % redis.incr('order_number'),
                    pay_type=validated_data.get('pay_type')
                )

                doctor_info = DoctorModel.objects.filter(id=doctor_id).first()
                # 订单记录表创建完成，获取课程，生成订单详情数据，并外键增加
                # 获取最优的优惠劵
                # 订单总价   优惠活动以后的总价
                # 最终折扣价格
                total_discount_price = 0  # 最终折扣价格

                # 计算总价  --- 类型转换的报错
                detail_list = []
                discount_name = validated_data.get('discount_name', "通用类型")
                is_public = validated_data.get('is_public', 0)
                answer_id = redis.hget(f'{user_id}:{doctor_id}:{patients_id}:1', 'answer_id').decode()
                answer = AnswerModel.objects.filter(id=answer_id).first()
                answer.is_public = is_public
                answer.save()
                # 计算最终优惠价格
                if user_coupon1:
                    # 获取当前用户选择优惠劵，获取id   -100  *0.8
                    sale = user_coupon1.coupon.sale[1:]
                    if user_coupon1.coupon.discount == 1:
                        # 减免  ---   类型转换错误   最终优惠价格
                        total_discount_price = float(sale)
                        # total_discount_price = real_price - float(sale)
                    elif user_coupon1.coupon.discount == 2:
                        # 类型转换问题，报错
                        total_discount_price = float(doctor_info.price) * (1-float(sale))

                # 给订单赋值，课程总价，实际付款金额
                orders.total_price = doctor_info.price
                # 实际付款金额
                orders.real_price = float(doctor_info.price) - total_discount_price
                orders.save()

                detail_list.append(OrdersDetailModel(
                    order=orders,
                    answer=answer,
                    price=doctor_info.price,
                    real_price=float(doctor_info.price) - total_discount_price,
                    discount_name=discount_name
                ))
                # 一次性往数据库添加商品详情列表对象
                OrdersDetailModel.objects.bulk_create(detail_list)

                # 问题数据，需要将is_commit字段修改为1
                redis.hset(f'{user_id}:{doctor_id}:{patients_id}:1', 'is_commit', '1')

                # 优惠劵删除
                if user_coupon1:
                    # 将优惠劵从redis中删除
                    # 将优惠劵信息，绑定到订单中
                    user_coupon1.order = orders
                    user_coupon1.save()
                    redis = get_redis_connection('coupon')
                    redis.delete(f'{user_id}:{user_coupon_id}')
                return orders
            except Exception as ex:
                print('当前订单生成失败......')
                print(ex)
                # 打印异常的类型和描述
                print(f"An error occurred: {type(ex).__name__} - {ex}")
                # 打印异常的完整堆栈信息
                traceback.print_exc()
                # 事务回滚
                transaction.savepoint_rollback(t1)
                raise serializers.ValidationError(detail='订单生成失败，请稍后再试...', code='order_error')


class OrderDetailModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = OrdersDetailModel
        fields = '__all__'


class OrderListModelSerializer(serializers.ModelSerializer):
    order_detail = OrderDetailModelSerializer(many=True)

    class Meta:
        model = OrdersModel
        fields = ['id', 'total_price', 'real_price', 'order_number', 'order_status', 'pay_type', 'order_desc', 'pay_time', 'coupon', 'order_detail', 'created_time']


